package com.ly.base.chapter03;

import java.util.*;
import java.util.stream.Stream;

import static java.util.stream.Collectors.*;

/**
 * 分组: GroupingBy
 * GroupingBy(组名,下游收集器)
 */
public class AMGroupingByDemo {
    record Hero(String name, int strength) { }

    public static void main(String[] args) {
        Stream<Hero> stream = Stream.of(
                new Hero("令狐冲", 90),
                new Hero("风清扬", 98),
                new Hero("独孤求败", 100),
                new Hero("方证", 92),
                new Hero("东方不败", 98),
                new Hero("冲虚", 90),
                new Hero("向问天", 88),
                new Hero("任我行", 92),
                new Hero("不戒", 88)
        );

        /**
         * 1、根据名字长度分组，组内只保留武力值
         *  mapping(x -> y,dc)   套娃         dc ---- 下游收集器别名
         */
//        Map<Integer, List<Integer>> result = stream.collect(groupingBy(t -> t.name().length(), mapping(Hero::strength, toList())));

        /**
         * 2、根据名字长度分组，分组后过滤掉武力小于90的
         * filtering(x -> boolean,dc)  ---- 先分组，后过滤
         */
//        Map<Integer, List<Integer>> result = stream.collect(groupingBy(t -> t.name().length(), filtering(t -> t.strength() >= 90, mapping(Hero::strength, toList()))));
//        Map<Integer, List<Hero>> result = stream.collect(groupingBy(t -> t.name().length(), filtering(t -> t.strength() >= 90, toList())));

        /**
         * 先过滤，在分组 --- 无需filtering(x -> boolean,dc)过滤器
         */
//        Map<Integer, List<Hero>> result = stream.filter(hero -> hero.strength() >= 90).collect(groupingBy(t -> t.name().length(), toList()));

        /**
         * 3、根据名字长度分组，分组后组内保留人名，并且人名切分为单个字符
         * flatMapping(x -> substream,dc)
         */
//        "东方不败".chars().mapToObj(Character::toString).forEach(System.out::print);//东方不败
//        System.out.println();

        //{2=[方, 证, 冲, 虚, 不, 戒], 3=[令, 狐, 冲, 风, 清, 扬, 向, 问, 天, 任, 我, 行], 4=[独, 孤, 求, 败, 东, 方, 不, 败]}
//        Map<Integer, List<String>> result = stream.collect(groupingBy(h ->
//                 h.name().length(),
//                 flatMapping(
//                        h -> h.name().chars().mapToObj(Character::toString),
//                        toList())
//                 )
//        );

        /**
         * 4、根据名字长度分组，分组后求每组个数
         * counting()
         */
        //{2=3, 3=4, 4=2}
//        Map<Integer, Long> result = stream.collect(groupingBy(h -> h.name().length(), counting()));

        /**
         * 5、根据名字长度分组，分组后求每组武功 最低 的人
         * minBy((a,b)->int)
         */
        // 使用Stream API对英雄进行分组并找到每组中力量最小的英雄
        // 分组依据是英雄名字的长度，选择最小的英雄是根据力量属性进行比较
        // 如果力量相同，则通过特定的排序规则进行进一步排序
//        Map<Integer, Optional<Hero>> result = stream.collect(groupingBy(h -> h.name().length(), minBy((a, b) -> {
//            // 比较两个英雄的力量大小
//            int strengthComparison = a.strength() - b.strength();
//            // 如果力量相同，通过特定规则排序保证稳定性
//            return strengthComparison != 0 ? strengthComparison : a.strength() == b.strength() ? -1 : 1;
//        })));

//        Map<Integer, Optional<Hero>> result = stream.collect(groupingBy(h -> h.name().length(), minBy(Comparator.comparing(Hero::strength))));

        /**
         * 6、根据名字长度分组，分组后求每组武功 最高 的人
         * maxBy((a,b)->int)
         */
//        Map<Integer, Optional<Hero>> result = stream.collect(groupingBy(h -> h.name().length(), maxBy(Comparator.comparing(Hero::strength))));

        /**
         * 7、根据名字长度分组，分组后求每组武功 和
         * sumingInt(x -> int)
         */
//        Map<Integer, Integer> result = stream.collect(groupingBy(h -> h.name().length(), summingInt(Hero::strength)));

        /**
         * 8、根据名字长度分组，分组后求每组武功 平均值
         * averagingDouble(x -> double)
         */
//        Map<Integer, Double> result = stream.collect(groupingBy(h -> h.name().length(), averagingDouble(Hero::strength)));

        /**
         * reducing(init,(p,x) -> r)
         */
        //求和
        Map<Integer, Integer> result = stream.collect(groupingBy(h -> h.name().length(), mapping(Hero::strength, reducing(0, (p, x) -> p + x))));

        System.out.println(result);
    }
}
